package com.atguigu.daijia.map.service.impl;

import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.common.constant.SystemConstant;
import com.atguigu.daijia.common.result.DriverStatusEnum;
import com.atguigu.daijia.common.result.Result;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import com.atguigu.daijia.common.util.Convert;
import com.atguigu.daijia.driver.client.DriverInfoFeignClient;
import com.atguigu.daijia.map.service.LocationService;
import com.atguigu.daijia.model.entity.driver.DriverSet;
import com.atguigu.daijia.model.form.map.SearchNearByDriverForm;
import com.atguigu.daijia.model.form.map.UpdateDriverLocationForm;
import com.atguigu.daijia.model.form.map.UpdateOrderLocationForm;
import com.atguigu.daijia.model.vo.driver.DriverSetVo;
import com.atguigu.daijia.model.vo.map.NearByDriverVo;
import com.atguigu.daijia.model.vo.map.OrderLocationVo;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class LocationServiceImpl implements LocationService {

    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private DriverInfoFeignClient driverInfoFeignClient;

    /*
     * @param locationForm
     * @==============History===============<br/>
     * @Description //   开启接单服务:更新司机经纬度位置
     * @Date 2024-8-24 23:11 
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return java.lang.Boolean
     */
    @Override
    public Boolean updateDriverLocation(UpdateDriverLocationForm locationForm)
    {
        BigDecimal longitude = locationForm.getLongitude();// 经度
        BigDecimal latitude = locationForm.getLatitude();// 维度
        String driverId = Convert.toStr(locationForm.getDriverId());// 司机id
        Point point = new Point(Convert.toDouble(longitude),Convert.toDouble(latitude));
        redisTemplate.opsForGeo().add(RedisConstant.DRIVER_GEO_LOCATION,point,driverId);
        return true;
    }

    /*
     * @param driverId 司机id
     * @==============History===============<br/>
     * @Description //   关闭接单服务:删除司机经纬度位置
     * @Date 2024-8-24 23:11 
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return java.lang.Boolean
     */
    @Override
    public Boolean removeDriverLocation(Long driverId)
    {
        redisTemplate.opsForGeo().remove(RedisConstant.DRIVER_GEO_LOCATION,Convert.toStr(driverId));
        return true;
    }

    /*
     * @param nearDriverForm
     * @==============History===============<br/>
     * @Description //   搜索附近满足条件的司机
     * @Date 2024-8-25 0:16
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return java.util.List<com.atguigu.daijia.model.vo.map.NearByDriverVo>
     */
    @Override
    public List<NearByDriverVo> searchNearByDriver(SearchNearByDriverForm nearDriverForm)
    {
        // 定义我们将来需要返回的集合对象
        List<NearByDriverVo> list = new ArrayList<>();

        BigDecimal longitude = nearDriverForm.getLongitude();// 经度
        BigDecimal latitude = nearDriverForm.getLatitude();// 维度
        BigDecimal mileageDistance = nearDriverForm.getMileageDistance();// 当前乘客的订单的里程数
        Point point = new Point(Convert.toDouble(longitude),Convert.toDouble(latitude));

        //定义距离，5公里
        Distance distance = new Distance(SystemConstant.NEARBY_DRIVER_RADIUS,
                    RedisGeoCommands.DistanceUnit.KILOMETERS);

        // 创建circle对象,point(当前位置) distance(距离)
        Circle circle = new Circle(point,distance);

        // 定义GEO参数，设置返回结果包含内容
        RedisGeoCommands.GeoRadiusCommandArgs args =
                RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                                                    .includeDistance()  // 包含距离
                                                    .includeCoordinates() // 包含坐标
                                                    .sortAscending(); // 升序

        // 查询redis,获取到满足条件的记录
        GeoResults<RedisGeoCommands.GeoLocation<String>> radius
                  = redisTemplate.opsForGeo().radius(RedisConstant.DRIVER_GEO_LOCATION, circle, args);
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = radius != null ? radius.getContent() : null;


        if(!CollectionUtils.isEmpty(content))
        {
            Iterator<GeoResult<RedisGeoCommands.GeoLocation<String>>> iterator = content.iterator();
            if (iterator.hasNext())
            {
                do {
                    GeoResult<RedisGeoCommands.GeoLocation<String>> next = iterator.next();
                    Long driverId = Convert.toLong(next.getContent().getName());// 当时我们存到redis中的司机id
                    Point itemPoint = next.getContent().getPoint();// 位置信息

                    double distanceValue = next.getDistance().getValue();// 当前司机距离乘客的距离,接单里程
                    // 将当前的接单里程向上取整,保留两位
                    BigDecimal currentDistance =
                            new BigDecimal(distanceValue).setScale(2, RoundingMode.HALF_UP);

                    Result<DriverSetVo> driverSetResult = driverInfoFeignClient.getDriverSet(driverId);

                    if(Objects.equals(driverSetResult.getCode(), ResultCodeEnum.SUCCESS.getCode()))
                    {
                        DriverSetVo driverSet = driverSetResult.getData();
                        Integer status = driverSet.getServiceStatus();
                        // 当前司机的状态是在开始接单的状态在进入我们的判断
                        if(Objects.equals(status, DriverStatusEnum.START_SERVER_STATUS.getCode()))
                        {
                            // 判断当前司机的接单里程
                            BigDecimal acceptDistance = driverSet.getAcceptDistance();
                            // 如果当前订单的接单里程大于司机本身设置接单里程,将当前司机排除
                            if(acceptDistance.doubleValue() != 0
                                    && acceptDistance.subtract(currentDistance).doubleValue() < 0)
                            {
                                continue;
                            }

                            // 判断当前司机的订单里程
                            BigDecimal orderDistance = driverSet.getOrderDistance();
                            // 如果当前订单的里程数大于司机本身设置的订单里程,将当前司机排除
                            if(orderDistance.doubleValue() != 0
                                    && orderDistance.subtract(mileageDistance).doubleValue() <0 )
                            {
                                continue;
                            }

                            NearByDriverVo nearDriverVo = new NearByDriverVo();
                            nearDriverVo.setDriverId(driverId);
                            nearDriverVo.setDistance(currentDistance);
                            list.add(nearDriverVo);
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else
                    {
                        continue;
                    }
                } while (iterator.hasNext());
            }
        }
        return list;
    }

    /*
     * @param updateOrderLocationForm
     * @==============History===============<br/>
     * @Description //   司机赶往代驾起始点:更新订单地址到缓存  就是更新当前司机的一个地址
     * @Date 2024-9-10 22:32
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return java.lang.Boolean
     */
    @Override
    public Boolean updateOrderLocationToCache(UpdateOrderLocationForm updateOrderLocationForm) {

        OrderLocationVo orderLocationVo = new OrderLocationVo();
        orderLocationVo.setLongitude(updateOrderLocationForm.getLongitude());
        orderLocationVo.setLatitude(updateOrderLocationForm.getLatitude());

        String key = RedisConstant.UPDATE_ORDER_LOCATION + updateOrderLocationForm.getOrderId();
        redisTemplate.opsForValue().set(key,orderLocationVo);
        return true;
    }

    /*
     * @param orderId  订单id
     * @==============History===============<br/>
     * @Description //   司机赶往代驾起始点:获取订单经纬度位置
     * @Date 2024-9-10 22:55
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return com.atguigu.daijia.model.vo.map.OrderLocationVo
     */
    @Override
    public OrderLocationVo getCacheOrderLocation(Long orderId) {
        String key = RedisConstant.UPDATE_ORDER_LOCATION + orderId;
        return (OrderLocationVo)redisTemplate.opsForValue().get(key);
    }
}
